package com.company.project.util;
/*
 * @Description: 登录拦截器，通过注解添加需要登录的接口，用来拦截没有token的接口
 * @Author:         brilliantzhao
 * @CreateDate:     2019/5/30 14:29
 * @UpdateUser:
 * @UpdateDate:     2019/5/30 14:29
 * @UpdateRemark:
 * token 的验证过程和 token 的生成过程有关，在用户登录接口中，我使用的是用户的密码左右 token 的密钥进行加密
 * （因为服务器并没有对 token 进行存储，所以加密的密钥最好是一个用户更改密码之后会变的东西，我就直接用密码了），
 * 还将 user id 存到了 JWT token 的 audience 中，因此我们能够从 token 中知道用户是谁。
 * 具体的JWT token 的生成和验证过程可以看看我们项目中使用的 jar 包的文档
 */

import com.auth0.jwt.JWT;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.company.project.annotation.LoginRequired;
import com.company.project.controller.UserDealController;
import com.company.project.exception.AuthenticationException;
import com.company.project.model.User;
import com.company.project.service.UserService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class AuthenticationInterceptor implements HandlerInterceptor {
    @Autowired
    private UserService userService;

    @Autowired
    private UserDealController userDealController;

    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response, Object handler) throws Exception {
        // 如果不是映射到方法直接通过
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();

        // 判断接口是否需要登录
        LoginRequired methodAnnotation = method.getAnnotation(LoginRequired.class);
        // 有 @LoginRequired 注解，需要认证
        if (methodAnnotation != null) {
            // 执行认证
            String token = request.getHeader("token");  // 从 http 请求头中取出 token
            if (token == null) {
                // 无token，请重新登录
                throw new AuthenticationException("请重新登录");
            }
            int userId;
            try {
                userId = Integer.parseInt(JWT.decode(token).getAudience().get(0));  // 获取 token 中的 user id
            } catch (JWTDecodeException e) {
                // token无效，请重新登录
                throw new AuthenticationException("请重新登录");
            }
            User user = userService.findById(userId);
            if (user == null) {
                // 用户不存在，请重新登录
                throw new AuthenticationException("请重新登录");
            }
            user = userDealController.getUserInfoByToken(token);
            if (user == null) {
                // 用户不存在，请重新登录
                throw new AuthenticationException("请重新登录");
            }
            // 验证 token , 判断是否失效
            try {
                JWTUtil jwtUtil = new JWTUtil();
                jwtUtil.verifyToken(user.getPassword(), token);
            } catch (JWTVerificationException e) {
                // token无效，请重新登录
                throw new AuthenticationException("请重新登录");
            }
            request.setAttribute("currentUser", user);
            return true;
        }
        return true;
    }
}